<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='Ext-fx-Anim'>/**
</span> * @class Ext.fx.Anim
 *
 * This class manages animation for a specific {@link #target}. The animation allows
 * animation of various properties on the target, such as size, position, color and others.
 *
 * ## Starting Conditions
 * The starting conditions for the animation are provided by the {@link #from} configuration.
 * Any/all of the properties in the {@link #from} configuration can be specified. If a particular
 * property is not defined, the starting value for that property will be read directly from the target.
 *
 * ## End Conditions
 * The ending conditions for the animation are provided by the {@link #to} configuration. These mark
 * the final values once the animations has finished. The values in the {@link #from} can mirror
 * those in the {@link #to} configuration to provide a starting point.
 *
 * ## Other Options
 *  - {@link #duration}: Specifies the time period of the animation.
 *  - {@link #easing}: Specifies the easing of the animation.
 *  - {@link #iterations}: Allows the animation to repeat a number of times.
 *  - {@link #alternate}: Used in conjunction with {@link #iterations}, reverses the direction every second iteration.
 *
 * ## Example Code
 *
 *     @example
 *     var myComponent = Ext.create('Ext.Component', {
 *         renderTo: document.body,
 *         width: 200,
 *         height: 200,
 *         style: 'border: 1px solid red;'
 *     });
 *
 *     Ext.create('Ext.fx.Anim', {
 *         target: myComponent,
 *         duration: 1000,
 *         from: {
 *             width: 400 //starting width 400
 *         },
 *         to: {
 *             width: 300, //end width 300
 *             height: 300 // end height 300
 *         }
 *     });
 */
Ext.define('Ext.fx.Anim', {

    /* Begin Definitions */

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'],

    /* End Definitions */

<span id='Ext-fx-Anim-property-isAnimation'>    /**
</span>     * @property {Boolean} isAnimation
     * `true` in this class to identify an object as an instantiated Anim, or subclass thereof.
     */
    isAnimation: true,

<span id='Ext-fx-Anim-cfg-callback'>    /**
</span>     * @cfg {Function} callback
     * A function to be run after the animation has completed.
     */

<span id='Ext-fx-Anim-cfg-scope'>    /**
</span>     * @cfg {Function} scope
     * The scope that the {@link #callback} function will be called with
     */

<span id='Ext-fx-Anim-cfg-duration'>    /**
</span>     * @cfg {Number} duration
     * Time in milliseconds for a single animation to last. Defaults to 250. If the {@link #iterations} property is
     * specified, then each animate will take the same duration for each iteration.
     */
    duration: 250,

<span id='Ext-fx-Anim-cfg-delay'>    /**
</span>     * @cfg {Number} delay
     * Time to delay before starting the animation. Defaults to 0.
     */
    delay: 0,

    /* private used to track a delayed starting time */
    delayStart: 0,

<span id='Ext-fx-Anim-cfg-dynamic'>    /**
</span>     * @cfg {Boolean} dynamic
     * Currently only for Component Animation: Only set a component's outer element size bypassing layouts.  Set to true to do full layouts for every frame of the animation.  Defaults to false.
     */
    dynamic: false,

<span id='Ext-fx-Anim-cfg-easing'>    /**
</span>     * @cfg {String} easing
This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
speed over its duration.

         -backIn
         -backOut
         -bounceIn
         -bounceOut
         -ease
         -easeIn
         -easeOut
         -easeInOut
         -elasticIn
         -elasticOut
         -cubic-bezier(x1, y1, x2, y2)

Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
be in the range [0, 1] or the definition is invalid.

[0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag

     * @markdown
     */
    easing: 'ease',

<span id='Ext-fx-Anim-cfg-keyframes'>     /**
</span>      * @cfg {Object} keyframes
      * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
      * is considered '100%'.&lt;b&gt;Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
      * &quot;from&quot; or &quot;to&quot;&lt;/b&gt;.  A keyframe declaration without these keyframe selectors is invalid and will not be available for
      * animation.  The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
      * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
 &lt;pre&gt;&lt;code&gt;
keyframes : {
    '0%': {
        left: 100
    },
    '40%': {
        left: 150
    },
    '60%': {
        left: 75
    },
    '100%': {
        left: 100
    }
}
 &lt;/code&gt;&lt;/pre&gt;
      */

<span id='Ext-fx-Anim-property-damper'>    /**
</span>     * @private
     */
    damper: 1,

<span id='Ext-fx-Anim-property-bezierRE'>    /**
</span>     * @private
     */
    bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,

<span id='Ext-fx-Anim-cfg-reverse'>    /**
</span>     * Run the animation from the end to the beginning
     * Defaults to false.
     * @cfg {Boolean} reverse
     */
    reverse: false,

<span id='Ext-fx-Anim-property-running'>    /**
</span>     * Flag to determine if the animation has started
     * @property running
     * @type Boolean
     */
    running: false,

<span id='Ext-fx-Anim-property-paused'>    /**
</span>     * Flag to determine if the animation is paused. Only set this to true if you need to
     * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
     * @property paused
     * @type Boolean
     */
    paused: false,

<span id='Ext-fx-Anim-cfg-iterations'>    /**
</span>     * Number of times to execute the animation. Defaults to 1.
     * @cfg {Number} iterations
     */
    iterations: 1,

<span id='Ext-fx-Anim-cfg-alternate'>    /**
</span>     * Used in conjunction with iterations to reverse the animation each time an iteration completes.
     * @cfg {Boolean} alternate
     * Defaults to false.
     */
    alternate: false,

<span id='Ext-fx-Anim-property-currentIteration'>    /**
</span>     * Current iteration the animation is running.
     * @property currentIteration
     * @type Number
     */
    currentIteration: 0,

<span id='Ext-fx-Anim-property-startTime'>    /**
</span>     * Starting time of the animation.
     * @property startTime
     * @type Date
     */
    startTime: 0,

<span id='Ext-fx-Anim-property-propHandlers'>    /**
</span>     * Contains a cache of the interpolators to be used.
     * @private
     * @property propHandlers
     * @type Object
     */

<span id='Ext-fx-Anim-cfg-target'>    /**
</span>     * @cfg {String/Object} target
     * The {@link Ext.fx.target.Target} to apply the animation to.  This should only be specified when creating an Ext.fx.Anim directly.
     * The target does not need to be a {@link Ext.fx.target.Target} instance, it can be the underlying object. For example, you can
     * pass a Component, Element or Sprite as the target and the Anim will create the appropriate {@link Ext.fx.target.Target} object
     * automatically.
     */

<span id='Ext-fx-Anim-cfg-from'>    /**
</span>     * @cfg {Object} from
     * An object containing property/value pairs for the beginning of the animation.  If not specified, the current state of the
     * Ext.fx.target will be used. For example:
&lt;pre&gt;&lt;code&gt;
from : {
    opacity: 0,       // Transparent
    color: '#ffffff', // White
    left: 0
}
&lt;/code&gt;&lt;/pre&gt;
     */

<span id='Ext-fx-Anim-cfg-to'>    /**
</span>     * @cfg {Object} to
     * An object containing property/value pairs for the end of the animation. For example:
 &lt;pre&gt;&lt;code&gt;
 to : {
     opacity: 1,       // Opaque
     color: '#00ff00', // Green
     left: 500
 }
 &lt;/code&gt;&lt;/pre&gt;
     */
    
    // private
    frameCount: 0,

    // @private
    constructor: function(config) {
        var me = this,
            curve;
            
        config = config || {};
        // If keyframes are passed, they really want an Animator instead.
        if (config.keyframes) {
            return new Ext.fx.Animator(config);
        }
        Ext.apply(me, config);
        if (me.from === undefined) {
            me.from = {};
        }
        me.propHandlers = {};
        me.config = config;
        me.target = Ext.fx.Manager.createTarget(me.target);
        me.easingFn = Ext.fx.Easing[me.easing];
        me.target.dynamic = me.dynamic;

        // If not a pre-defined curve, try a cubic-bezier
        if (!me.easingFn) {
            me.easingFn = String(me.easing).match(me.bezierRE);
            if (me.easingFn &amp;&amp; me.easingFn.length == 5) {
                curve = me.easingFn;
                me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
            }
        }
        me.id = Ext.id(null, 'ext-anim-');
        me.addEvents(
<span id='Ext-fx-Anim-event-beforeanimate'>            /**
</span>             * @event beforeanimate
             * Fires before the animation starts. A handler can return false to cancel the animation.
             * @param {Ext.fx.Anim} this
             */
            'beforeanimate',
<span id='Ext-fx-Anim-event-afteranimate'>             /**
</span>              * @event afteranimate
              * Fires when the animation is complete.
              * @param {Ext.fx.Anim} this
              * @param {Date} startTime
              */
            'afteranimate',
<span id='Ext-fx-Anim-event-lastframe'>             /**
</span>              * @event lastframe
              * Fires when the animation's last frame has been set.
              * @param {Ext.fx.Anim} this
              * @param {Date} startTime
              */
            'lastframe'
        );
        me.mixins.observable.constructor.call(me);
        Ext.fx.Manager.addAnim(me);
    },

<span id='Ext-fx-Anim-method-setAttr'>    /**
</span>     * @private
     * Helper to the target
     */
    setAttr: function(attr, value) {
        return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
    },

<span id='Ext-fx-Anim-method-initAttrs'>    /**
</span>     * @private
     * Set up the initial currentAttrs hash.
     */
    initAttrs: function() {
        var me = this,
            from = me.from,
            to = me.to,
            initialFrom = me.initialFrom || {},
            out = {},
            start, end, propHandler, attr;

        for (attr in to) {
            if (to.hasOwnProperty(attr)) {
                start = me.target.getAttr(attr, from[attr]);
                end = to[attr];
                // Use default (numeric) property handler
                if (!Ext.fx.PropertyHandler[attr]) {
                    if (Ext.isObject(end)) {
                        propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object;
                    } else {
                        propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler;
                    }
                }
                // Use custom handler
                else {
                    propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr];
                }
                out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr);
            }
        }
        me.currentAttrs = out;
    },

<span id='Ext-fx-Anim-method-start'>    /**
</span>     * @private
     * Fires beforeanimate and sets the running flag.
     */
    start: function(startTime) {
        var me = this,
            delay = me.delay,
            delayStart = me.delayStart,
            delayDelta;
        
        if (delay) {
            if (!delayStart) {
                me.delayStart = startTime;
                return;
            }
            else {
                delayDelta = startTime - delayStart;
                if (delayDelta &lt; delay) {
                    return;
                }
                else {
                    // Compensate for frame delay;
                    startTime = new Date(delayStart.getTime() + delay);
                }
            }
        }
        if (me.fireEvent('beforeanimate', me) !== false) {
            me.startTime = startTime;
            if (!me.paused &amp;&amp; !me.currentAttrs) {
                me.initAttrs();
            }
            me.running = true;
            me.frameCount = 0;
        }
    },

<span id='Ext-fx-Anim-method-runAnim'>    /**
</span>     * @private
     * Calculate attribute value at the passed timestamp.
     * @returns a hash of the new attributes.
     */
    runAnim: function(elapsedTime) {
        var me = this,
            attrs = me.currentAttrs,
            duration = me.duration,
            easingFn = me.easingFn,
            propHandlers = me.propHandlers,
            ret = {},
            easing, values, attr, lastFrame;

        if (elapsedTime &gt;= duration) {
            elapsedTime = duration;
            lastFrame = true;
        }
        if (me.reverse) {
            elapsedTime = duration - elapsedTime;
        }

        for (attr in attrs) {
            if (attrs.hasOwnProperty(attr)) {
                values = attrs[attr];
                easing = lastFrame ? 1 : easingFn(elapsedTime / duration);
                ret[attr] = propHandlers[attr].set(values, easing);
            }
        }
        me.frameCount++;
            
        return ret;
    },

<span id='Ext-fx-Anim-method-lastFrame'>    /**
</span>     * @private
     * Perform lastFrame cleanup and handle iterations
     * @returns a hash of the new attributes.
     */
    lastFrame: function() {
        var me = this,
            iter = me.iterations,
            iterCount = me.currentIteration;

        iterCount++;
        if (iterCount &lt; iter) {
            if (me.alternate) {
                me.reverse = !me.reverse;
            }
            me.startTime = new Date();
            me.currentIteration = iterCount;
            // Turn off paused for CSS3 Transitions
            me.paused = false;
        }
        else {
            me.currentIteration = 0;
            me.end();
            me.fireEvent('lastframe', me, me.startTime);
        }
    },

    endWasCalled: 0,

<span id='Ext-fx-Anim-method-end'>    /**
</span>     * Fire afteranimate event and end the animation. Usually called automatically when the
     * animation reaches its final frame, but can also be called manually to pre-emptively
     * stop and destroy the running animation.
     */
    end: function() {
        if (this.endWasCalled++) {
            return;
        }
        var me = this;
        me.startTime = 0;
        me.paused = false;
        me.running = false;
        Ext.fx.Manager.removeAnim(me);
        me.fireEvent('afteranimate', me, me.startTime);
        Ext.callback(me.callback, me.scope, [me, me.startTime]);
    },
    
    isReady: function() {
        return this.paused === false &amp;&amp; this.running === false &amp;&amp; this.iterations &gt; 0;
    },
    
    isRunning: function() {
        return this.paused === false &amp;&amp; this.running === true &amp;&amp; this.isAnimator !== true;
    }
});
// Set flag to indicate that Fx is available. Class might not be available immediately.
Ext.enableFx = true;
</pre>
</body>
</html>
